; RUN: llvm-profgen --format=text --perfscript=%S/Inputs/coroutine.perfscript --binary=%S/Inputs/coroutine.perfbin --output=%t
; RUN: FileCheck %s --input-file %t --check-prefix=CHECK

; Check that the head sample count for ticker is 0.
; CHECK: _Z6tickeri:1566:0
; CHECK-NOT: _Z6tickeri.resume


/*
 * Inputs/coroutine.perfbin is generated by compiling the following source code:
 * clang++ coroutine.cpp -std=c++2a -g2 -o coroutine
 */

#include <cstdint>
#include <cstdlib>
#include <ctime>
#include <experimental/coroutine>
#include <iostream>

struct task {
  struct promise_type {
    task get_return_object() { return {}; }
    std::experimental::suspend_never initial_suspend() { return {}; }
    std::experimental::suspend_never final_suspend() noexcept { return {}; }
    void return_void() {}
    void unhandled_exception() {}
  };
};

template <typename T>
struct generator {
  struct promise_type;
  using handle = std::experimental::coroutine_handle<promise_type>;
  struct promise_type {
    int current_value;
    static auto get_return_object_on_allocation_failure() { return generator{nullptr}; }
    auto get_return_object() { return generator{handle::from_promise(*this)}; }
    auto initial_suspend() { return std::experimental::suspend_always{}; }
    auto final_suspend() { return std::experimental::suspend_always{}; }
    void unhandled_exception() { std::terminate(); }
    void return_void() {}
    auto yield_value(int value) {
      current_value = value;
      return std::experimental::suspend_always{};
    }
  };
  bool move_next() { return coro ? (coro.resume(), !coro.done()) : false; }
  int current_value() { return coro.promise().current_value; }
  generator(generator const &) = delete;
  generator(generator &&rhs) : coro(rhs.coro) { rhs.coro = nullptr; }
  ~generator() {
    if (coro)
      coro.destroy();
  }

private:
  generator(handle h) : coro(h) {}
  handle coro;
};

generator<int> ticker(int count) {
  for (int i = 0; i < count; ++i) {
    srand(time(NULL));
    uint32_t a = rand() % 10 + 1;
    uint32_t b = rand() % 10 + 1;
    uint64_t c = 0;
    for (int i = 0; i < 1500; ++i) {
      c = ((uint64_t)a) + b;
      a = b;
      b = c % 2147483648ULL;
    }
    co_yield a;
  }
}

int main() {
  auto g = ticker(500000);
  uint64_t ans = 0;
  while (g.move_next()) {
    ans += g.current_value();
  }
  std::cout << ans << "\n";
}
